Skip to content

feat(governance): MS Agent Framework adapter#361

Open
aditik0303 wants to merge 12 commits into
mainfrom
feat/governance-agent-framework
Open

feat(governance): MS Agent Framework adapter#361
aditik0303 wants to merge 12 commits into
mainfrom
feat/governance-agent-framework

Conversation

@aditik0303

@aditik0303 aditik0303 commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Adds a Microsoft Agent Framework governance adapter to uipath-agent-framework. It lets UiPath governance evaluate what an agent_framework agent does at the model and tool level, and block disallowed actions, without the agent author writing governance code. This package contains only the Agent-Framework-specific bridge.

What it does

  • Detects an agent_framework.BaseAgent and installs governance by prepending a ChatMiddleware and a FunctionMiddleware to agent.middleware (governance runs first; existing middleware is preserved). For workflow agents it installs on each inner agent.

  • Each middleware brackets its call and maps to a governance check:

    Agent Framework middleware Governance hook
    ChatMiddleware — before the model call BEFORE_MODEL
    ChatMiddleware — after the model call AFTER_MODEL
    FunctionMiddleware — before the tool call TOOL_CALL
    FunctionMiddleware — after the tool call AFTER_TOOL
  • Enforces by letting a GovernanceBlockException (raised on a DENY decision) propagate, stopping the model call or tool. Any other error inside a governance hook is logged and swallowed, so a governance failure cannot break an otherwise-healthy agent run.

  • Installed by the runtime factory: passing an evaluator to new_runtime wires governance onto the resolved agent in place. No adapter registry, no entry point, no import-time registration.

What it does not do

  • Does not fire agent-level boundaries (BEFORE_AGENT / AFTER_AGENT); those are owned by the governance host.
  • Does not depend on platform, auth, transport, or runtime internals — only on the shared governance contracts in uipath-core.

aditik0303 and others added 2 commits June 22, 2026 23:09
Appends a ChatMiddleware (BEFORE/AFTER_MODEL) and FunctionMiddleware (TOOL_CALL/AFTER_TOOL) to agent.middleware; walks WorkflowAgent executors for multi-agent apps.

Self-registers via the uipath.governance.adapters entry point; unit-tested and verified firing through the framework's real execution path. BEFORE/AFTER_AGENT remain owned by the uipath-runtime wrapper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…, framework-only can_handle)

Mirror radu's LangChain-adapter review across the MS Agent Framework adapter:
- __init__: drop the import-time registration side-effect; registration only via the uipath.governance.adapters entry point.
- can_handle: claim only a real agent_framework.BaseAgent; remove the duck-typed (middleware + run/workflow) fallback.
- docstring: 'governance host' instead of uipath-runtime internals.
- tests: can_handle uses a real BaseAgent; duck-typed look-alikes are now rejected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 24, 2026 12:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Microsoft Agent Framework governance adapter to uipath-agent-framework, wired via entry-point discovery, and aligns runtime/model plumbing with upstream client API changes.

Changes:

  • Introduces an Agent Framework governance adapter + middleware that fires BEFORE_MODEL/AFTER_MODEL and TOOL_CALL/AFTER_TOOL hooks.
  • Adds a governance adapter entry point and new uipath-core dependency, plus corresponding lockfile updates.
  • Updates chat client construction and runtime schema model-name extraction to prefer model (with model_id fallback).

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/uipath-agent-framework/uv.lock Locks in the new uipath-core dependency for the package.
packages/uipath-agent-framework/pyproject.toml Adds uipath-core dependency and a uipath.governance.adapters entry point for governance adapter discovery.
packages/uipath-agent-framework/src/uipath_agent_framework/governance/adapter.py New governance adapter + middleware implementation for Agent Framework agents and workflows.
packages/uipath-agent-framework/src/uipath_agent_framework/governance/init.py Provides register_governance_adapter() and avoids import-time registration; exposes public symbols.
packages/uipath-agent-framework/tests/governance/test_adapter.py New unit tests covering can_handle, attach/detach, hook bracketing, blocking behavior, and exception swallowing.
packages/uipath-agent-framework/tests/governance/init.py Adds governance test package marker.
packages/uipath-agent-framework/src/uipath_agent_framework/runtime/schema.py Updates model-name extraction to support client.model with model_id fallback.
packages/uipath-agent-framework/src/uipath_agent_framework/chat/openai.py Updates OpenAI client initialization to pass model= instead of model_id=.
packages/uipath-agent-framework/src/uipath_agent_framework/chat/anthropic.py Updates Anthropic client initialization to pass model= instead of model_id=.
packages/uipath-agent-framework/src/uipath_agent_framework/_cli/_templates/main.py.template Updates template usage to OpenAIChatClient(model=...).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/uipath-agent-framework/src/uipath_agent_framework/governance/adapter.py Outdated
Comment thread packages/uipath-agent-framework/src/uipath_agent_framework/runtime/schema.py Outdated
aditik0303 and others added 10 commits June 24, 2026 18:34
…apter

Module docstring: registers via the uipath.governance.adapters entry point, not at import time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The model/model_id chat-client tweak in runtime/schema.py is unrelated to the governance adapter and was bundled in accidentally. Revert it to main so this PR is governance-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These files were swept into the branch by a broad add; they are unrelated to the governance adapter. Reverting/removing them so the PR contains only governance changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An earlier cleanup commit compared against a stale local main and wrongly removed SETUP.MD and reverted the LlamaIndex docs change. Both files come from main (PRs #352/#356), not this branch. Restore them to the main version so this PR is governance-only with no spurious deletions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Record that payload text is read via `.text` rather than isinstance on
agent-framework message/response models, since those shapes are still
pre-release (rc) and not stable public types.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…valuator

Core PR #1761 removed BaseAdapter from uipath-core. Migrate to the
factory-evaluator pattern (matching #899):

- governance/adapter.py -> middleware.py: replace the BaseAdapter
  subclass (name/can_handle/attach/detach) with module-level
  install_governance() that appends the governance middleware to each
  agent's middleware list (walking WorkflowAgent executors); keep the
  middleware classes + callbacks. File named for its seam (middleware).
- runtime/factory.py: new_runtime reads `evaluator` from kwargs and
  calls install_governance.
- governance/__init__.py: drop register_governance_adapter + registry
  import; expose install_governance. No import-time side effects.
- pyproject.toml: remove the uipath.governance.adapters entry point.
- tests (test_adapter.py -> test_middleware.py): drop can_handle/attach/
  detach; cover install_governance + factory wiring.

ruff + mypy clean; 14 governance tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review findings (Viswa) for PR #361:

- AFTER_MODEL / AFTER_TOOL now run inside a try/finally around call_next,
  so they still fire (audit + rules observe the turn) when the model or
  tool call raises. GovernanceBlockException from before_* still aborts
  before call_next; the underlying error still propagates after the finally.
- Streaming AFTER_MODEL: on a streaming ChatContext, context.result is a
  ResponseStream after call_next (reading it yielded empty text). We now
  register a stream_result_hook so AFTER_MODEL runs on the finalized
  ChatResponse the framework assembles once the stream is consumed.
- Drop the per-callbacks uuid trace_id (identical for every call); trace
  correlation is owned by the layer below, matching LangChain. Requires
  uipath-core >= 0.5.20 (removed trace_id from EvaluatorProtocol) — bumped.
- Count llm/tool calls only after governance passes: a DENY raised before
  the bump, inflating the counter on blocked calls.
- Cap _stringify output so an oversized tool result / message can't hand a
  multi-megabyte string to the evaluator.
- Trailing newline (W292).

Note: agents are not cached by the factory (each runtime gets a fresh
instance to avoid concurrent-Workflow reuse), so the cached-agent
re-attach concern does not apply here — the idempotency guard is only a
double-install safety net. The PR description's entry-point claim is stale
(factory-evaluator uses no governance entry-point) and will be corrected.

Tests: added finally-on-error (model + tool), streaming result-hook, and
no-inflation-on-block coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to the #361 review pass — the earlier commit covered streaming
(stream_result_hook), try/finally, trace_id, counters, and the _stringify cap;
these are the rest:

- middleware.py:113 (walk gap — page-2 theme + minor 8) — _iter_agents now
  RECURSES through nested WorkflowAgents (workflow-of-workflows). Before it
  stopped one level down, so a nested workflow's inner agents ran ungoverned.
  Converted to an explicit stack walk with a _MAX_GRAPH_NODES cap that logs
  when it trips (was a silent inline `len(seen) < 1000`).
- middleware.py:326 (_coerce_args) — log a warning when model_dump() fails
  instead of silently dropping the tool args from governance visibility.
- middleware.py:135 (nit) — inverted the empty-targets check to a guard clause.

Tests: nested-workflow recursion + cycle-safety (self-referential executor);
streaming + AFTER_MODEL-on-error were added in the earlier pass. 141 pass.

Acknowledged, unchanged: latest-message-only scan (same documented tradeoff as
#899); cached-agent re-attach does not apply — this factory does not cache
agents (fresh per runtime) and trace_id is no longer held.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same pre-existing CI-lint failure (mypy runs over tests):
- FakeEvaluator evaluate_* -> (self, *args, **kwargs) -> Any; bare dict ->
  dict[str, Any].
- typed the duck-typed contexts as  so passing a SimpleNamespace
  to process()'s ChatContext/FunctionInvocationContext param type-checks
  (one inline context keeps an arg-type ignore).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…overage)

New-code coverage ~89% -> over the 90% gate. Added non-block swallow on every
callback, _message_text/_response_text/_latest_message_text edges, and
_coerce_args variants incl. the model_dump-failure warn branch.
governance/middleware.py: 85% -> 97%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 1, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants